#include "BoxList.h"
#include "qmenu.h"
#include "qtreewidget.h"
#include "qobjectdefs.h"
#include "qcoreevent.h"
#include "WidgetsMenu.h"
#include "Router.h"
#include "qboxlayout.h"
#include "qevent.h"
#include "qlist.h"
#include "QItemDelegate"
#include "Selections.h"
#include "qfiledialog.h"
#include "qdebug.h"
#include "Accesser.h"
#include "QClipboard.h"

class Tree : public QTreeWidget
{
public:
    Tree(QWidget* parent) : QTreeWidget(parent) {}
protected:
    virtual void dropEvent(QDropEvent* event)
    {
        QTreeWidgetItem* item = itemAt(event->pos());
        event->ignore();
    }
};

BoxList::BoxList(QWidget *parent)
	: QWidget(parent)
	, _index(0)
    , _copyed(nullptr)
    , _ctrlPress(false)
{
    ui.setupUi(this);

    QVBoxLayout* verticalLayout = new QVBoxLayout(this);
    verticalLayout->setSpacing(0);
    verticalLayout->setObjectName(QStringLiteral("verticalLayout"));
    verticalLayout->setContentsMargins(0, 0, 0, 0);
    _treeWidget = new Tree(this);

    _root = new TreeItem();
    _root->setText("1");
    _treeWidget->setHeaderItem(_root);
    _treeWidget->setSelectionMode(QAbstractItemView::NoSelection);

    _treeWidget->setObjectName(QStringLiteral("treeWidget"));
    _treeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
    _treeWidget->header()->setVisible(false);

    verticalLayout->addWidget(_treeWidget);

    this->setLayout(verticalLayout);

    _treeWidget->setDragDropMode(QAbstractItemView::InternalMove);
    connect(_treeWidget, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(checkNameAndVisible(QTreeWidgetItem*, int)));
    connect(_treeWidget, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(showMenu(const QPoint&)));
   // connect(_treeWidget, SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)), this, SLOT(selectedNode(QTreeWidgetItem*, QTreeWidgetItem*)));
    //connect(_treeWidget, SIGNAL(itemSelectionChanged()), this, SLOT(itemSelectionChanged()));
    connect(_treeWidget, SIGNAL(itemClicked(QTreeWidgetItem*, int)), 
        this, SLOT(onClick(QTreeWidgetItem*, int)));
    
}

BoxList::~BoxList()
{

}

void BoxList::onClick(QTreeWidgetItem* curr, int)
{
    _currentWidget = (TreeItem*)curr;
    if (_ctrlPress)
    {
        if (_currentWidget)
        {
            if (_currentWidget->isSelected())
            {
                _currentWidget->setSelected(false);
                Selection::getInstance().remove(_currentWidget->getWidget());
            }
            else
            {
                Selection::getInstance().add(_currentWidget->getWidget());
            }
        }
    }
    else
    {
        Selection::getInstance().selected(
            _currentWidget ? _currentWidget->getWidget() : nullptr);
    }
}

void BoxList::itemSelectionChanged()
{
}

void BoxList::checkNameAndVisible(QTreeWidgetItem* item, int)
{
    emit onItemTextChanged((TreeItem*)item);
}

void BoxList::selectedNode(QTreeWidgetItem* curr, QTreeWidgetItem* prev)
{

}

TreeItem* BoxList::add(const QString& type, const QString& name, QTreeWidgetItem* parent /* = nullptr */)
{

	TreeItem *item = TreeItem::create();
	item->setCheckState(0, Qt::Checked);

    item->QTreeWidgetItem::setText(0, name);

    if (parent == nullptr)
        _treeWidget->addTopLevelItem(item);
    else
        parent->addChild(item);

	return item;
}

void BoxList::showMenu(const QPoint& pos)
{
    _currentWidget = (TreeItem*)_treeWidget->itemAt(pos);
    QClipboard* qc = QApplication::clipboard();

    bool show = (!!_currentWidget) && (_currentWidget != _root);
    widgetsMenu* menu = widgetsMenu::create(this)
        ->cfg(widgetsMenu::kDelete, show)
        ->cfg(widgetsMenu::kCopy, show)
        ->cfg(widgetsMenu::kCode, true)
        ->cfg(widgetsMenu::kCodeCpp, true)
        ->cfg(widgetsMenu::kSave, show)
        ->cfg(widgetsMenu::kAddFrom, show)
        ->cfg(widgetsMenu::kPaste, !(qc->text().isNull() || qc->text().isEmpty()));

    connect(menu, SIGNAL(onAdd(const QString&)), this, SLOT(onAdd(const QString&)));
    connect(menu, SIGNAL(onTouch(int)), this, SLOT(onTouchMenu(int)));

    menu->showAtPos();
}

void BoxList::onTouchMenu(int k)
{
    if (k == widgetsMenu::kDelete)
        onDelete();
    else if (k == widgetsMenu::kCopy)
        onCopy();
    else if (k == widgetsMenu::kPaste)
        onPaste();
    else if (k == widgetsMenu::kSave)
        onSave();
    else if (k == widgetsMenu::kAddFrom)
        onAddFrom();
    else if (k == widgetsMenu::kCode)
        onCode();
    else if (k == widgetsMenu::kCodeCpp)
        onCodeCpp();
}

void BoxList::onAddFrom()
{
    QString filePath = QFileDialog::getOpenFileName(this, tr("Choose a File"), "", tr("XXFiles (*.xx)"));
    if (filePath.isNull())
        return;

    QList<TreeItem*> items = Accesser::fromFile(filePath);

    for (auto item : items)
    {
        _currentWidget->addChild(item);
        _currentWidget->getWidget()->addChild(item->getWidget());
        item->getWidget()->release();
    }
}

void BoxList::onCodeCpp()
{
    if (_currentWidget)
    {
        QList<TreeItem*> lst;
        lst.append(_currentWidget);
        QString s = Accesser::getCodeCpp(lst);
        QClipboard* qc = QApplication::clipboard();
        qc->setText(s);
    }
    else
    {
        QString s = Accesser::getCodeCpp(getTopLevelItems());
        QClipboard* qc = QApplication::clipboard();
        qc->setText(s);
    }
}

void BoxList::onCode()
{
    if (_currentWidget)
    {
        QList<TreeItem*> lst;
        lst.append(_currentWidget);
        QString s = Accesser::getCode(lst);
        QClipboard* qc = QApplication::clipboard();
        qc->setText(s);
    }
    else
    {
        QString s = Accesser::getCode(getTopLevelItems());
        QClipboard* qc = QApplication::clipboard();
        qc->setText(s);
    }
}

void BoxList::onCopy()
{
    if (_currentWidget)
    {
        QList<TreeItem*> lst;

        lst.append(_currentWidget);
        QString s = Accesser::toString(lst);
        QClipboard* qc = QApplication::clipboard();

        qc->setText(s);

        //_copyed = _currentWidget;
    }
}

static TreeItem* clone(TreeItem* from)
{
    TreeItem* item = TreeItem::create();

    item->setWidget(from->getWidget()->clone());
    item->getWidget()->removeAllChildren();
    item->setText(from->getWidget()->getName());

    for (int i = 0; i < from->childrenCount(); i++)
    {
        TreeItem* child = from->childrenAtIndex(i);
        TreeItem* child_copy = clone(child);

        item->addChild(child_copy);
        item->getWidget()->addChild(child_copy->getWidget());
    }

    return item;
}


void BoxList::onPaste()
{
    QClipboard* qc = QApplication::clipboard();
    if (qc->text().isNull() || qc->text().isEmpty())
    {
        return;
    }

    QList<TreeItem*> items = Accesser::fromString(qc->text());

    if (_currentWidget)
    {
        for (TreeItem* item : items)
        {
            _currentWidget->addChild(item);
            _currentWidget->getWidget()->addChild(item->getWidget());
            item->getWidget()->release();
        }
    }
    else
    {
        for (TreeItem* item : items)
        {
            _treeWidget->addTopLevelItem(item);
            _root->getWidget()->addChild(item->getWidget());
            item->getWidget()->release();
        }
    }
}

void BoxList::onSave()
{
    QString filePath = QFileDialog::getSaveFileName(this, tr("Choose a File"), "File.xx", tr("XXFiles (*.xx)"));

    if (filePath.isNull() || filePath.isEmpty())
        return;

    QList<TreeItem*> lst;
    lst.append(_currentWidget);

    QFile file(filePath);

    file.open(QIODevice::WriteOnly);
    file.write(Accesser::toString(lst).toUtf8());
    file.close();
}

void BoxList::onDelete()
{
    emit onDeleteItem(_currentWidget);

    if (_copyed == _currentWidget)
        _copyed = nullptr;

    delete _currentWidget;
}

void BoxList::onAdd(const QString& type)
{
    QString name = type + "_" + QString::number(_index++);

    TreeItem* newItem = add(type, name, _currentWidget);

    if (_currentWidget) {
        newItem->parent = _currentWidget;
        _currentWidget->setExpanded(true);
    }
    else {
        newItem->parent = _root;
    }

    emit onAddItem(newItem, name, type);

    Selection::getInstance().selected(newItem->getWidget());
}

static TreeItem* find(TreeItem* t, Widget* w)
{
    if (t->getWidget() == w)
        return t;

    for (int i = 0; i < t->childrenCount(); i++)
    {
        TreeItem* item = find(t->childrenAtIndex(i), w);
        if (item) return item;
    }

    return nullptr;
}

TreeItem* BoxList::findItem(Widget* w)
{
    for (int i = 0; i < _treeWidget->topLevelItemCount(); i++)
    {
        TreeItem* fd = ::find((TreeItem*)_treeWidget->topLevelItem(i), w);
        if (fd)
            return fd;
    }

    return nullptr;
}

QList<TreeItem*> BoxList::getTopLevelItems()
{
    QList<TreeItem*> items;

    for (int i = 0; i < _treeWidget->topLevelItemCount(); i++)
    {
        items.append((TreeItem*)_treeWidget->topLevelItem(i));
    }
    return items;
}

void BoxList::onOpen(const QList<TreeItem*>& itms)
{
    for (int i = 0; i < _treeWidget->topLevelItemCount(); i++)
        emit onDeleteItem((TreeItem*)_treeWidget->topLevelItem(i));

    _treeWidget->clear();

    for (QList<TreeItem*>::const_iterator it = itms.begin(); it != itms.end(); it++)
    {
        TreeItem* item = *it;
        _treeWidget->addTopLevelItem(item);
        item->parent = _root;
        _root->getWidget()->addChild(item->getWidget());
        item->getWidget()->release();
    }
}

void BoxList::onSelectionChanged()
{
    for (auto item : _treeWidget->selectedItems())
    {
        item->setSelected(false);
    }

    auto set = Selection::getInstance().get();

    TreeItem* item = nullptr;
    for (auto w : set)
    {
        item = findItem(w);
        if (item)
        {
            item->setSelected(true);
            _treeWidget->setCurrentItem(item);
        }
        else
        {
            CCLog("not found.");
        }
    }

    if (set.size() == 1)
        _currentWidget = item;
}

void BoxList::keyPressEvent(QKeyEvent *event)
{
    if (event->key() == Qt::Key_Control && !event->isAutoRepeat())
        _ctrlPress = true;
}

void BoxList::keyReleaseEvent(QKeyEvent *event)
{
    if (event->key() == Qt::Key_Control && !event->isAutoRepeat())
        _ctrlPress = false;
}
